#!/usr/bin/python

import os
import shutil
import tempfile
import unittest

import s2d
import util


TEST_OPML = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<opml version="1.0">
    <head>
        <title>test3</title>
        <dateCreated>2011-08-23 15:02:28 -0700</dateCreated>
    </head>
    <body>
        <outline text="Preface" _note="This is the preface for this test data.&#10;&#10;It consists of two paragraphs."></outline>
        <outline text="First" _note="This is the first section.  It&apos;s a simple section.  It&apos;s &lt;emphasis&gt;really&lt;/emphasis&gt; simple.  Alice &amp;amp; Bob approve.&#10;&#10;&lt;programlisting&gt;&#10;# This is a simple code sample.&#10;def fun(val):&#10;    return x * 100&#10;&#10;for x in xrange(100):&#10;    print x  &#10;&lt;/programlisting&gt;">
            <outline text="Sub-first One" _note="Here&apos;s a sub-section, the first of many."></outline>
            <outline text="Sub-first Two" _note="Here&apos;s another sub-section.  For good measure, I&apos;m going to give it a sub-section as well.">
                <outline text="Sub-first Sub-two One" _note="And here it is."></outline>
            </outline>
            <outline text="Sub-first Three" _note="This is quite a bit of test data.  It was created in Scrivener in order to resemble a real-world example."></outline>
        </outline>
        <outline text="Second" _note="My second chapter.">
            <outline text="Sub-second" _note="One more sub-section, for good measure.&#10;&#10;This sub-section has multiple paragraphs."></outline>
        </outline>
        <outline text="Third" _note="My third and final chapter.&#10;&#10;The end.&#10;"></outline>
    </body>
</opml>
"""


TEXT_THREE_PARA_TWO_PROGRAMLISTING = """
This is some text that resembles a real-world scenario.  This is a
paragraph of text, on multiple lines.

<programlisting>
# Here is a programlisting.

def fun(val):
    val *= 100

for x in xrange(100):
    print fun(x)
</programlisting>

Here is another paragraph.

<programlisting>foo.sh bar baz</programlisting>

And finally one more paragraph.
"""


RESULT_THREE_PARA_TWO_PROGRAMLISTING = """<para>This is some text that resembles a real-world scenario.  This is a
paragraph of text, on multiple lines.</para>

<programlisting>
# Here is a programlisting.

def fun(val):
    val *= 100

for x in xrange(100):
    print fun(x)
</programlisting>

<para>Here is another paragraph.</para>

<programlisting>foo.sh bar baz</programlisting>

<para>And finally one more paragraph.</para>"""


class TestRegexps(unittest.TestCase):
    def testChapterFnameMatches(self):
        m = s2d.RE_CHAPTER_FNAME.match('ch09_Test_Title.xml')
        self.assertIsNotNone(m)
        m = s2d.RE_CHAPTER_FNAME.match('ch09.xml')
        self.assertIsNotNone(m)

    def testChapterFnameDoesNotMatch(self):
        m = s2d.RE_CHAPTER_FNAME.match('dedication.xml')
        self.assertIsNone(m)
        m = s2d.RE_CHAPTER_FNAME.match('colo.xml')
        self.assertIsNone(m)

    def testBookXmlChapterMatches(self):
        m = s2d.RE_BOOK_XML_CHAPTER.match('  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch09_Test_Title.xml"/>')
        self.assertIsNotNone(m)

    def testBookXmlChapterDoesNotMatch(self):
        m = s2d.RE_BOOK_XML_CHAPTER.match('  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="colo.xml"/>')
        self.assertIsNone(m)
        m = s2d.RE_BOOK_XML_CHAPTER.match('  <index />')
        self.assertIsNone(m)


# TODO: OPMLParser


class TestParseOpml(unittest.TestCase):
    def testParseOpml(self):
        top_sections = s2d.parse_opml(TEST_OPML)
        self.assertEqual(4, len(top_sections))
        self.assertEqual('Preface', top_sections[0].title)
        self.assertEqual('First', top_sections[1].title)
        self.assertEqual('Second', top_sections[2].title)
        self.assertEqual('Third', top_sections[3].title)


class TestAutoPara(unittest.TestCase):
    def testZeroParas(self):
        result = s2d.auto_para(
            '')
        self.assertEqual(
            '<para></para>',
            result)

    def testOnePara(self):
        result = s2d.auto_para(
            'some text')
        self.assertEqual(
            '<para>some text</para>',
            result)

    def testTwoParas(self):
        result = s2d.auto_para(
            'some text\n\nsome more text')
        self.assertEqual(
            '<para>some text</para>\n\n<para>some more text</para>',
            result)

    def testTwoParasOneProgramlistingInMiddle(self):
        result = s2d.auto_para(
            'some text\n\n'
            '<programlisting>listing text</programlisting>\n\n'
            'some more text')
        self.assertEqual(
            '<para>some text</para>\n\n'
            '<programlisting>listing text</programlisting>\n\n'
            '<para>some more text</para>',
            result)

    def testTwoParasOneProgramlistingAtStart(self):
        result = s2d.auto_para(
            '<programlisting>listing text</programlisting>\n\n'
            'some text\n\n'
            'some more text')
        self.assertEqual(
            '<programlisting>listing text</programlisting>\n\n'
            '<para>some text</para>\n\n'
            '<para>some more text</para>',
            result)

    def testTwoParasOneProgramlistingAtEnd(self):
        result = s2d.auto_para(
            'some text\n\n'
            'some more text\n\n'
            '<programlisting>listing text</programlisting>')
        self.assertEqual(
            '<para>some text</para>\n\n'
            '<para>some more text</para>\n\n'
            '<programlisting>listing text</programlisting>',
            result)

    def testThreeParaTwoProgramlisting(self):
        result = s2d.auto_para(TEXT_THREE_PARA_TWO_PROGRAMLISTING)
        self.assertEqual(
            RESULT_THREE_PARA_TWO_PROGRAMLISTING,
            result)

    def testFigureBug(self):
        data = """The Windows and Mac OS X versions of the Python SDK include an application called the Google App Engine Launcher (hereafter just "Launcher"). With the Launcher, you can create and manage multiple App Engine Python projects using a graphical interface. <xref linkend="launcher_window"/> shows an example of the Launcher window in Mac OS X.

<figure float="none" id="launcher_window">
          <title>The Google App Engine Launcher for Mac OS X main window, with
          a project selected</title>
          <mediaobject id="I_mediaobject2_d1e1136">
            <imageobject role="print">
              <imagedata fileref="figs/print/pgae_0201.pdf" format="PDF"/>
            </imageobject>
            <imageobject role="web">
              <imagedata fileref="figs/web/pgae_0201.png" format="PNG"/>
            </imageobject>
          </mediaobject>

</figure>

To create a new project..."""
        result = s2d.auto_para(data)
        self.assertEqual("""<para>The Windows and Mac OS X versions of the Python SDK include an application called the Google App Engine Launcher (hereafter just "Launcher"). With the Launcher, you can create and manage multiple App Engine Python projects using a graphical interface. <xref linkend="launcher_window"/> shows an example of the Launcher window in Mac OS X.</para>

<figure float="none" id="launcher_window">
          <title>The Google App Engine Launcher for Mac OS X main window, with
          a project selected</title>
          <mediaobject id="I_mediaobject2_d1e1136">
            <imageobject role="print">
              <imagedata fileref="figs/print/pgae_0201.pdf" format="PDF"/>
            </imageobject>
            <imageobject role="web">
              <imagedata fileref="figs/web/pgae_0201.png" format="PNG"/>
            </imageobject>
          </mediaobject>

</figure>

<para>To create a new project...</para>""", result)


class TestDocBookTextForSection(unittest.TestCase):
    def testDocBookTextForSection(self):
        sec = util.Section(
            'section_id',
            'Title',
            'text')
        self.assertEqual(
            '\n<chapter id="section_id">\n'
            '<title>Title</title>\n\n'
            '<para>text</para>\n\n'
            '</chapter>\n',
            s2d.get_docbook_text_for_section(sec))


class TestMakeChapterFiles(unittest.TestCase):
    def setUp(self):
        self.output_dir = tempfile.mkdtemp()

    def tearDown(self):
        shutil.rmtree(self.output_dir)

    def testMakeChapterFiles(self):
        top_sections = s2d.parse_opml(TEST_OPML)
        result = s2d.make_chapter_files(self.output_dir, top_sections)

        self.assertIn('ch00_Preface.xml', result)
        self.assertIn('ch01_First.xml', result)
        self.assertIn('ch02_Second.xml', result)
        self.assertIn('ch03_Third.xml', result)

        self.assertTrue(
            os.path.isfile(os.path.join(self.output_dir, 'ch00_Preface.xml')))
        self.assertTrue(
            os.path.isfile(os.path.join(self.output_dir, 'ch01_First.xml')))
        self.assertTrue(
            os.path.isfile(os.path.join(self.output_dir, 'ch02_Second.xml')))
        self.assertTrue(
            os.path.isfile(os.path.join(self.output_dir, 'ch03_Third.xml')))

        fh = open(os.path.join(self.output_dir, 'ch00_Preface.xml'))
        text = fh.read()
        fh.close()
        self.assertIn('<?xml version="1.0"', text)
        self.assertIn('<!DOCTYPE preface PUBLIC', text)
        self.assertIn('<preface id=', text)
        self.assertIn('<title>Preface</title>', text)
        self.assertIn('<para>This is the preface', text)

        fh = open(os.path.join(self.output_dir, 'ch01_First.xml'))
        text = fh.read()
        fh.close()
        self.assertIn('<?xml version="1.0"', text)
        self.assertIn('<!DOCTYPE chapter PUBLIC', text)
        self.assertIn('<chapter id=', text)
        self.assertIn('<title>First</title>', text)
        self.assertIn('<para>This is the first section.', text)


class TestUpdateBookXml(unittest.TestCase):
    def setUp(self):
        self.output_dir = tempfile.mkdtemp()

    def tearDown(self):
        shutil.rmtree(self.output_dir)

    def testUpdateBookXmlCreatesNewFile(self):
        s2d.update_book_xml(
            self.output_dir,
            ['ch00_Preface.xml',
             'ch01_First.xml',
             'ch02_Second.xml',
             'ch03_Third.xml'])
        book_path = os.path.join(self.output_dir, 'book.xml')
        self.assertTrue(os.path.isfile(book_path))
        fh = open(book_path)
        text = fh.read()
        fh.close()

        self.assertIn('<?xml version="1.0"', text)
        self.assertIn('<!DOCTYPE book PUBLIC', text)
        self.assertIn('<book id=', text)
        self.assertIn('<title><!-- INSERT TITLE HERE --></title>', text)
        self.assertIn('href="ch00_Preface.xml"', text)
        self.assertIn('href="ch01_First.xml"', text)
        self.assertIn('href="ch02_Second.xml"', text)
        self.assertIn('href="ch03_Third.xml"', text)
        self.assertIn('</book>', text)
        
    def testUpdateBookXmlUpdatesExistingFile(self):
        book_path = os.path.join(self.output_dir, 'book.xml')
        fh = open(book_path, 'w')
        fh.write("""<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">

<book id="some_book_id">
  <title>My Great Book</title>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="dedication.xml"/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch00_Preface.xml"/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch01_Introduction.xml"/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch02_First.xml"/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch03_Second.xml"/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch04_Third.xml"/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="ch05_Last.xml"/>
  <index/>
  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="colo.xml"/>
</book>
""")
        fh.close()

        s2d.update_book_xml(
            self.output_dir,
            ['ch00_Preface.xml',
             'ch01_First.xml',
             'ch02_Second.xml',
             'ch03_Third.xml'])
        self.assertTrue(os.path.isfile(book_path))
        fh = open(book_path)
        text = fh.read()
        fh.close()

        self.assertIn('<?xml version="1.0"', text)
        self.assertIn('<!DOCTYPE book PUBLIC', text)
        self.assertIn('<book id=', text)
        self.assertNotIn('<title><!-- INSERT TITLE HERE --></title>', text)
        self.assertIn('<title>My Great Book</title>', text)
        self.assertIn('href="dedication.xml"', text)
        self.assertIn('href="ch00_Preface.xml"', text)
        self.assertIn('href="ch01_First.xml"', text)
        self.assertIn('href="ch02_Second.xml"', text)
        self.assertIn('href="ch03_Third.xml"', text)
        self.assertNotIn('href="ch05_Last.xml"', text)
        self.assertIn('href="colo.xml"', text)
        self.assertIn('</book>', text)


# TODO: class TestSvnAssist(unittest.TestCase)
# TODO: class TestValidateXml(unittest.TestCase)
# TODO: class TestS2DMain(unittest.TestCase)


if __name__ == '__main__':
    unittest.main()
